package com.ywz.framework.aspectj;

import cn.hutool.jwt.JWT;
import com.ywz.common.JWTUtils;
import com.ywz.common.StringUtils;
import com.ywz.project.base.system.entity.TSysOperLog;
import com.ywz.project.base.system.service.TSysOperLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.Arrays;

/**
 * 类描述 -> 操作日志切面
 *
 * @Author: ywz
 * @Date: 2024/09/13
 */
@Component
@Slf4j
@Aspect
public class SysOperLogAspectj {

    private static final String POINT_CUT = "execution(* com.ywz.project.*.controller.*.*(..))";
    @Resource
    private TSysOperLogService service;


    /**
     * 方法描述 -> 后置通知记录操作日志
     *
     * @param joinPoint 连接点
     * @param result    返回值
     * @Author: ywz
     * @Date: 2024/09/05
     */
    @AfterReturning(pointcut = POINT_CUT, returning = "result")
    public void afterReturningLog(JoinPoint joinPoint, Object result) {
        TSysOperLog sysOperLog = new TSysOperLog();
        // 添加请求参数
        if (joinPoint.getArgs() != null) {
            sysOperLog.setOperParam(StringUtils.subSpecifiedString(Arrays.toString(joinPoint.getArgs()), 2000));
        }
        // 添加返回结果集
        if (result != null) {
            sysOperLog.setJsonResult(StringUtils.subSpecifiedString(result.toString(), 2000));
        }
        sysOperLog.setStatus(0);
        saveLog(sysOperLog, joinPoint.getSignature());
    }

    /**
     * 方法描述 -> 异常通知记录操作日志
     *
     * @param joinPoint 连接点
     * @param e         异常
     * @Author: ywz
     * @Date: 2024/09/05
     */
    @AfterThrowing(pointcut = POINT_CUT, throwing = "e")
    public void afterThrowingLog(JoinPoint joinPoint, Exception e) {
        TSysOperLog sysOperLog = new TSysOperLog();
        // 添加请求参数
        if (joinPoint.getArgs() != null) {
            sysOperLog.setOperParam(StringUtils.subSpecifiedString(Arrays.toString(joinPoint.getArgs()), 2000));
        }
        // 添加异常信息
        if (!StringUtils.isEmpty(e.getMessage()))
            sysOperLog.setErrorMsg(StringUtils.subSpecifiedString(e.getMessage(), 2000));
        sysOperLog.setStatus(1);
        saveLog(sysOperLog, joinPoint.getSignature());
    }

    /**
     * 方法描述 -> 异常通知记录操作日志
     *
     * @Author: ywz
     * @Date: 2024/09/05
     */
    private void saveLog(TSysOperLog sysOperLog, Signature signature) {
        // 获取请求的方法名
        String methodName = signature.getName();
        sysOperLog.setTitle(methodName);
        // 设置业务类型
        if (methodName.contains("add") || methodName.contains("save")) {
            sysOperLog.setBusinessType(1);
        } else if (methodName.contains("upd") || methodName.contains("edit")) {
            sysOperLog.setBusinessType(2);
        } else if (methodName.contains("del") || methodName.contains("remove")) {
            sysOperLog.setBusinessType(3);
        } else {
            sysOperLog.setBusinessType(4);
        }
        // 获取请求方法详情
        String methodString = signature.toString();
        sysOperLog.setMethod(StringUtils.subSpecifiedString(methodString, 255));
        // 获取请求对象
        RequestAttributes ra = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes sra = (ServletRequestAttributes) ra;
        if (sra != null) {
            HttpServletRequest request = sra.getRequest();
            // 获取请求的IP
            sysOperLog.setOperIp(request.getRemoteAddr());
            // 获取请求的URL
            sysOperLog.setOperUrl(request.getRequestURL().toString());
            // 获取请求的方法
            sysOperLog.setRequestMethod(request.getMethod());
            // 获取请求的浏览器类型
            String userAgent = request.getHeader("User-Agent");
            if (userAgent != null && (userAgent.contains("Windows") || userAgent.contains("Macintosh"))) {
                sysOperLog.setOperatorType(1);
            } else if (userAgent != null && userAgent.contains("Mobile")) {
                sysOperLog.setOperatorType(2);
            } else {
                sysOperLog.setOperatorType(0);
            }
            // 获取token中存储的信息，此处需要根据登录实际存储作相应的更改
            if (!StringUtils.isEmpty(request.getHeader("token"))) {
                JWT token = JWTUtils.getTokenInfo(request.getHeader("token"));
                sysOperLog.setOperName(token.getPayload("username").toString());
                // sysOperLog.setDeptName(token.getPayload("deptName").toString());
            }
        }
        sysOperLog.setCreateTime(LocalDateTime.now());
        // 保存操作记录
        try {
            service.save(sysOperLog);
        } catch (Exception e) {
            log.error("保存操作日志异常");
        }
    }
}
